package com.example.gcmtest1.httpserver;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;

import org.apache.http.Header;
import org.apache.http.HttpMessage;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.impl.DefaultHttpRequestFactory;
import org.apache.http.impl.DefaultHttpServerConnection;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.io.HttpRequestParser;
import org.apache.http.impl.io.SocketInputBuffer;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;

import android.content.Context;
import android.util.Log;

public class HttpBuilder extends Thread {

	private String logName = "HttpBuilder";
	
	private Socket socket;
	private DefaultHttpServerConnection serverConnection;
	private Context context;
	
	public HttpBuilder(Context context, Socket socket) {
		this.context = context;
		this.socket = socket;
		
		this.serverConnection = new DefaultHttpServerConnection();
        
		
		
	}

	@Override
	public void run() {
		super.run();
		
		MyFileWriter fw = null;
		
		try {
			this.serverConnection.bind(socket, new BasicHttpParams());
			Log.d(logName, "HttpBuilder.run() Starting.. hashCode=" + String.valueOf(this.socket.hashCode()));
			
			BasicHttpParams httpParams = new BasicHttpParams();
									
			SocketInputBuffer inBuffer = new SocketInputBuffer(this.socket, HttpConnectionParams.getSocketBufferSize(httpParams), httpParams);
			HttpRequestParser reqParser = new HttpRequestParser(inBuffer, null, new DefaultHttpRequestFactory(), httpParams);
			HttpRequest request = (HttpRequest) reqParser.parse();
			
			if (request != null) {
				for (Header h : request.getAllHeaders()) {
					Log.d(logName, h.getName() + ": " + h.getValue());
				}	
			} else {
				Log.e(logName, "http is null, parse failed");
			}
			
			String uri = request.getRequestLine().getUri();
			Log.i(logName, "uri=" + uri);
			
			String[] ss = uri.split("/");
			int i = 0;
			for (String s : ss) {
				Log.d(logName, "[" + String.valueOf(i) + "]=" + s);
				i += 1;
			}
			
			String hostName = ss[2];
			String destUri = "http://" + this.getDestinationUrl(ss);
			Log.i(logName, "host=" + hostName);
			Log.i(logName, "destUri=" + destUri);
			
			
			String fileName = ss[ss.length-1];
			Log.i(logName, "fileName=" + fileName);
			
			fw = new MyFileWriter(this.context, fileName);
			
			HttpRequestBase httpBase = null;
			HttpClient httpClient = new DefaultHttpClient();
			
			if (request.getRequestLine().getMethod().equals("GET")) {
				httpBase = new HttpGet(destUri);
			} else if (request.getRequestLine().getMethod().equals("POST")) {
				httpBase = new HttpPost(destUri);
			}
			
			for (Header h : request.getAllHeaders()) {
				if (!(h.getName().toLowerCase().equals("host"))) {
					httpBase.addHeader(h);
					Log.d(logName, "Appended Header: " + h.getName() + "=" + h.getValue());
				} else {
					httpBase.addHeader("host", hostName);
					Log.d(logName, "Appended Header: host=" + hostName);
					
				}
			}
			
			
			
			Log.d(logName, "Sending Request: " + destUri);
			
			 // Execute HTTP Request
	        HttpResponse resp = httpClient.execute(httpBase);
	        InputStream ins = resp.getEntity().getContent();
	        
	        FileInputStream fi = new FileInputStream(this.context.getFileStreamPath(fileName).toString());
	        ins = (InputStream) fi;
	        
	        long length = resp.getEntity().getContentLength();
			
	        Log.d(logName, "==== Response Header ====");
	        String respHeader = this.listAllHeader(resp.getAllHeaders());
	        Log.d(logName, respHeader);
	        
	        int position = 0;
	        int chunkSize = 1024 * 1024;
	        byte[] bb = new byte[chunkSize];
	        
	        int readLen;
	        	        	        
	        String httpString = "HTTP/1.1 200 OK\r\n";
	        for (Header h2 : resp.getAllHeaders()) {
	        	httpString = httpString + h2.getName() + ": " + h2.getValue() + "\r\n";
	        }
	        
	        httpString = httpString + "\r\n";
	        
	        Log.d(logName, "httpString=\n" + httpString);
	        
	        byte[] buffer = httpString.toString().getBytes();
	        socket.getOutputStream().write(buffer, 0, buffer.length);	        
	        
	        //ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
	        
	        while (position < length) {
	        	readLen = chunkSize;
	        	
	        	if (position + chunkSize > length) {
	        		readLen = (int) (length - position);
	        	}
	        	
	        	if (readLen != chunkSize) {
	        		bb = new byte[readLen];	
	        	}
	        	
	        	int len = ins.read(bb);
	        	//Log.d(logName, "len=" + String.valueOf(len) + ", available=" + String.valueOf(ins.available()));
	        	
	        	this.socket.getOutputStream().write(bb, 0, len);
	        	//byteBuffer.write(bb, 0, len);
	        	
	        	if (fw != null) {
	        		fw.append(bb, 0, len);	
	        	}
	        	
	        		        		        		        		        		        			        	        
	        	position = position + len;
	        	//Log.d(logName, "position:" + String.valueOf(position));
	        	
	        }
	        
	        ins.close();	        
	        
			
		} catch (Exception e) {
			Log.e(logName, e.toString() + ", hashCode=" + String.valueOf(this.socket.hashCode()));
			Log.e(logName, "isBound=" + this.socket.isBound() + ", isClosed=" + this.socket.isClosed() + ", isConnected=" + this.socket.isConnected() + ", isInputDown=" + this.socket.isInputShutdown() + ", isOutputDown=" + this.socket.isOutputShutdown());
			e.printStackTrace();
		}
		
		/*
		if (this.socket.isClosed() == false) {
			try {
				Log.d(logName, "trying to close Socket, hashCode=" + String.valueOf(this.socket.hashCode()));
				this.socket.close();
				Log.d(logName, "Closed Socket, hashCode=" + String.valueOf(this.socket.hashCode()));
			} catch (Exception e) {
				
			}
			
		}		
		*/
		
		try {
			//this.serverConnection.shutdown();	
		} catch (Exception e) {
			
		}
		
		Log.d(logName, "HttpBuilder.run() done.. hashCode=" + String.valueOf(this.socket.hashCode()));
		
		if (fw != null) {
			fw.closeFile();
		}
				
	}	
	
	/*
	@Override
	public void run() {
		super.run();
		
		try {
			Log.d(logName, "Starting..");
			BufferedReader r = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
			StringBuilder total = new StringBuilder();
			String line;
			while ((line = r.readLine()) != null) {
			    total.append(line + "\r\n");
			    Log.d(logName, line);
			    
			    if (line.equals("\r\n")) {
			    	
			    	Log.d(logName, "... exit");
			    	break;
			    }
			}
			
			this.socket.close();
			Log.d(logName, "done..");
		} catch (Exception e) {
			Log.e(logName, e.toString());
			e.printStackTrace();
		}
				
	}
	*/
	
	public void startThread() {
		super.start();
	}
	
	private String getDestinationUrl(String[] ss) {
		int i = 2;
		String destUri = "";
		for (i = 2; i < ss.length; i++) {
			if (i > 2) {
				destUri = destUri + "/";
			}
			
			destUri = destUri + ss[i];
		}
		
		return(destUri);
	}
	
	private String listAllHeader(Header[] hh) {
		StringBuffer sb = new StringBuffer();
		for (Header h : hh) {
			sb.append(h.getName() + ": " + h.getValue() + "\n");
		}
		
		return(sb.toString());
	}
	
}
